/**
 * \file draw.h
 * \brief Default drawing routines.
 * \author Corey Tabaka
 */

/*
   Copyright 2006 Corey Tabaka

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

#ifndef __DRAW_H__
#define __DRAW_H__

typedef struct {
	union {
		struct {
			uint8 b;
			uint8 g;
			uint8 r;
			uint8 a;
		} __attribute__ ((packed));
		uint32 color;
	};
} argb_t;

/*static inline sint16 abs(sint16 value) {
	return value > 0 ? value : -value;
}*/

#ifndef abs
#define abs(a) ((a) > 0 ? (a) : -(a))
#endif

static inline void swap(sint16 &a, sint16 &b) {
	sint16 tmp = b;
	b = a;
	a = tmp;
}

static inline void swap(uint32 &a, uint32 &b) {
	uint32 tmp = b;
	b = a;
	a = tmp;
}

static inline void plot(sint16 x, sint16 y, uint32 c) {
	if (x >= 0 && x < modeinfo.xResolution
		&& y >= 0 && y < modeinfo.yResolution) {
		uint32 *fb = (uint32 *) frameBuffer;
		fb[y*modeinfo.bytesPerScanLine/4 + x] = c;
	}
}

static inline void line(sint16 x0, sint16 y0, sint16 x1, sint16 y1, uint32 c) {
	bool steep = abs(y1 - y0) > abs(x1 - x0);
	
	if (steep) {
		swap(x0, y0);
		swap(x1, y1);
	}
	
	if (x0 > x1) {
		swap(x0, x1);
		swap(y0, y1);
	}
	
	int deltax = x1 - x0;
	int deltay = abs(y1 - y0);
	int error = 0;
	int y = y0;
	int ystep = y0 < y1 ? 1 : -1;
	
	for (int x = x0; x <= x1; x++) {
		if (steep) {
			plot(y, x, c);
		} else {
			plot(x, y, c);
		}
		
		error += deltay;
		
		if ((error<<1) >= deltax) {
			y += ystep;
			error -= deltax;
		}
	}
}

static inline void gradientLine(sint16 x0, sint16 y0, sint16 x1, sint16 y1,
	uint32 c0, uint32 c1) {
	bool steep = abs(y1 - y0) > abs(x1 - x0);
	
	if (steep) {
		swap(x0, y0);
		swap(x1, y1);
	}
	
	if (x0 > x1) {
		swap(x0, x1);
		swap(y0, y1);
		swap(c0, c1);
	}
	
	int deltax = x1 - x0;
	int deltay = abs(y1 - y0);
	int error = 0;
	int y = y0;
	int ystep = y0 < y1 ? 1 : -1;
	
	// each color component acts as a parallel y-axis, against the x-axis
	argb_t argb0, argb1;
	argb0.color = c0;
	argb1.color = c1;
	
	uint8 a, r, g, b;
	
	for (int x = x0; x <= x1; x++) {
		uint32 oneMinusAlpha = (x - x0) * 255 / (deltax < 1 ? 1 : deltax);
		uint32 alpha = 255 - oneMinusAlpha;
		
		a = (argb0.a * alpha  + argb1.a * oneMinusAlpha) >> 8;
		r = (argb0.r * alpha  + argb1.r * oneMinusAlpha) >> 8;
		g = (argb0.g * alpha  + argb1.g * oneMinusAlpha) >> 8;
		b = (argb0.b * alpha  + argb1.b * oneMinusAlpha) >> 8;
		
		if (steep) {
			plot(y, x, ((a << 24) | (r << 16) | (g << 8) | b));
		} else {
			plot(x, y, ((a << 24) | (r << 16) | (g << 8) | b));
		}
		
		error += deltay;
		
		if ((error<<1) >= deltax) {
			y += ystep;
			error -= deltax;
		}
	}
}

#endif
